package executor.service;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import executor.core.ExecutorProvider;

public class ExecutorProviderImpl implements ExecutorProvider {

	public ExecutorService executor;
	public Map<String, ThreadClass> mapOfThreads = new HashMap<>();
	public Map<String, Object> mapResult = new HashMap<>();

	public Map<String, Object> mapOutput = new ConcurrentHashMap<>();

	@Override
	public void beginExecutor() {
		executor = Executors.newFixedThreadPool(Runtime.getRuntime()
				.availableProcessors());
	}

	@Override
	public void bindThreadMethod(String methodName, String className,
			Object[] params, Class<?>[] object, Object instance) {
		ThreadClass classVar = new ThreadClass();
		classVar.setClassName(className);
		classVar.setMethodName(methodName);
		classVar.setClassArray(object);
		classVar.setArgumentArray(params);
		classVar.setInstance(instance);
		mapOfThreads.put(methodName, classVar);
	}

	@Override
	public void execute() throws InterruptedException {
		List<Callable<Object>> runnablesList = new ArrayList<>();

		Iterator<String> inputMapKeys = mapOfThreads.keySet().iterator();
		while (inputMapKeys.hasNext()) {
			String inputKeys = inputMapKeys.next();
			ThreadClass pojo = mapOfThreads.get(inputKeys);

			Object[] objectArray = pojo.argumentArray;

			Method m = null;
			Object i = null;
			try {
				Class<?> c = Class.forName(pojo.getClassName());
				m = c.getDeclaredMethod(pojo.getMethodName(), pojo.classArray);
				// try {
				// i = c.newInstance();
				i = pojo.getInstance();
				/*
				 * } catch (InstantiationException e) { // TODO Auto-generated
				 * catch block e.printStackTrace(); } catch
				 * (IllegalAccessException e) { // TODO Auto-generated catch :: Would Add Loggers
				 * block e.printStackTrace(); }
				 */
			} catch (NoSuchMethodException | SecurityException e) {
				// TODO Auto-generated catch block :: Would Add LOggers
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block :: Would Add Loggers
				e.printStackTrace();
			}
			ExecutorThread executorThread = new ExecutorThread();
			executorThread.setI(i);
			executorThread.setM(m);
			executorThread.setObjects(objectArray);

			runnablesList.add(executorThread);

		}

		List<Future<Object>> obj = executor.invokeAll(runnablesList);
		try {
			System.out.println(obj.get(0).get());
			System.out.println(obj.get(1).get());
			System.out.println(obj.get(2).get());

		} catch (ExecutionException e) {
			e.printStackTrace();
		}

	}

	@Override
	public Object getMethodResult(String methodName) {
		return mapResult.get(methodName);
	}

	@Override
	public void closeExecutor() {
		executor.shutdown();
	}

}
